# -*- coding: utf-8 -*-
"""
    projectmanager
    ~~~~~~~~~~~~~~

    Management of projects.

    :copyright: 2010 by Baptiste Lepilleur.
    :license: Apache License 2.0, see LICENSE.txt for more details.
"""
from tipfy import RequestHandler, Response, request, Unauthorized, NotFound
from tipfy.ext.db import get_entity_from_protobuf, get_protobuf_from_entity
import logging
from google.appengine.ext import db
from google.appengine.api import memcache
import re

MAX_PROJECT_SLUG_NAME_LENGTH = 16
MAX_PROJECT_NAME_LENGTH = 32
MAX_BRANCH_SLUG_NAME_LENGTH = 64

_REX_SLUG = re.compile( r'^[a-z0-9_\-~()\[\]|]*$' )

def slug_name_validator(max_length):
  def validator(value):
    if len(value) > max_length:
      raise ValueError( 'Maximum length is %d characters' % max_length )
    if not _REX_SLUG.match( value ):
      raise ValueError( 'Must contains only a-z, 0-9 and symbols _-[]()|')
  return validator

def max_length_validator(max_length):
  def validator(value):
    if len(value) > max_length:
      raise ValueError( 'Maximum length is %d characters' % max_length )
  return validator

class Project(db.Model):
    """A project has a unique id stored as the key name. It owns branches
       that owns build results.
    """
    editable_properties = ('slug_name', 'name')

    slug_name = db.StringProperty(verbose_name='Short Name',
      required=True,
      validator=slug_name_validator(MAX_PROJECT_SLUG_NAME_LENGTH))
    name = db.StringProperty(verbose_name='Display Name',
      required=True,
      validator=max_length_validator(MAX_PROJECT_NAME_LENGTH) )
    created = db.DateTimeProperty(verbose_name='Created',
      auto_now_add=True)
    modified = db.DateTimeProperty(verbose_name='Last Change',
      auto_now=True)
    #featured_branches = db.StringListProperty()



class Branch(db.Model):
    """A branch has a unique id stored as the key name.
       A branch belongs to a project and owns build results.
       A branch key name is composed of the project and the branch ids.
    """
    name = db.StringProperty(verbose_name='Display Name',
                             required=True)
    # Checkout url
    url = db.TextProperty(required=False)
    created = db.DateTimeProperty(verbose_name='Created',
                                  auto_now_add=True)
    modified = db.DateTimeProperty(verbose_name='Last Change',
                                   auto_now=True)


_project_by_slug_name = {}
_MAX_CACHED_SLUG_NAME = 32

_query_key_by_slug_name = db.GqlQuery(
    "SELECT __key__ FROM Project WHERE slug_name = :1",
    "dummy" )


def slug_name_to_id( slug_name ):
    """Returns the Project id corresponding to the specified slug_name.
    Return None if no project match the specified slug_name.
    1) Try to get it from memcache
    2) Retrieve from db & add to memcache
    """
    if len(slug_name) > MAX_PROJECT_SLUG_NAME_LENGTH:
        return None
    project_id = _project_by_slug_name.get( slug_name )
    if project_id is None:
        project_data = memcache.get( slug_name, namespace='Project.id:slug_name=' )
        if project_data is None:
            _query_key_by_slug_name.bind( slug_name )
            key = _query_key_by_slug_name.get()
            if key is None: # project does not exist
                return None
            project_id = key.id()
            memcache.set( slug_name, '%d' % project_id,
                          namespace='Project.id:slug_name=' )
        else:
            project_id = int(project_data)
        if len(_project_by_slug_name) >= _MAX_CACHED_SLUG_NAME:
            _project_by_slug_name = {}
        _project_by_slug_name[slug_name] = project_id
    return project_id

_query_by_slug_name = db.GqlQuery(
    "SELECT * FROM Project WHERE slug_name = :1",
    "dummy" )


def get_by_slug_name( slug_name ):
    if len(slug_name) > MAX_PROJECT_SLUG_NAME_LENGTH:
        return None
    _query_by_slug_name.bind( slug_name )
    return _query_by_slug_name.get()
